home *** CD-ROM | disk | FTP | other *** search
- unit glViewFr;
- (*
- *********************************************************************
- Unit glViewFrame
- Written by T. Beattie
- Created 22/5/98
- Last updated 22/5/98
- *********************************************************************
-
- Defines a TViewFrame object:
- Fields
- fViewer(x,y,z) position of viewer
- fLookAt(x,y,z) position being viewed
- fUpVect(x,y,z) vector defining up direction
- Methods
- RotateAboutViewer(HorAng,VerAng)
- RotateAboutLookAt(HorAng,VerAng)
- RotateUpVector(xRot,yRot)
- AdvanceToLookAt(Dist) {and rotate HorAng as well?}
- FlyBy(Dist{Speed},RollAng,PitchAng)
-
- All methods return a boolean result to indicate success.
- All rotation angles are relative, horizontal angles are anti-clockwise
- positive, vertical angles are up positive.
- Movement is described by moving fViewer on a sphere centred on
- fLookAt.
-
- Polar coordinates:
- r = distance from origin (>0)
- theta = horizontal bearing anti-clockwise from x-axis
- phi = vertical bearing, 0=horizontal, up=positive, abs(ph)<=90
- *)
-
- interface
-
- uses
- glFuncs;
-
- type
-
- TViewFrame = class(tObject)
- protected
- fViewer, //position of viewer
- fLookAt, //position being viewed
- fUpVect, //vector defining up direction
- fLeftEye, //left eye position
- fRightEye, //Right eye position
- fOrigin: tGLPoint; //Store original
- fPerspective : Boolean;
- fHeadLight : tGLLight;
- fRange,
- fViewAngle,
- fScreenZ : Double;
- fScale : Double;
- fXRadius,
- fYradius,
- fZRadius : Double;
-
- Procedure SetUpEyePositions;
- Procedure SetViewerPos(aVal:tGLPoint);
- //viewer doesn't own the headlight, it is supplied by the tGLLightWindow if
- Procedure SetXRadius(aVal:Double);
- Procedure SetYRadius(aVal:Double);
- Procedure SetZRadius(aVal:Double);
- public
-
- constructor Create;
- function Duplicate: TViewFrame;
- function RotateAboutViewer(HorAng,VerAng: single): boolean;
- function RotateAboutLookAt(HorAng,VerAng: single): boolean;
- function RotateUpVector(Ang: single): boolean;
- function AdvanceToLookAt(Dist: single): boolean;
- function FlyBy(Speed,RollAng,PitchAng: single): boolean;
- procedure MovePosition(DeltaX,DeltaY,DeltaZ: single);
- procedure MoveFrame(DeltaX,DeltaY,DeltaZ: single);
- procedure SetViewer3s(x,y,z: single);
- procedure SetLookAt3s(x,y,z: single);
- procedure SetUpVector3s(x,y,z: single);
- Procedure SetScale(aVal:Double);
- //jh mod
- procedure SetViewer3d(x,y,z: Double);
- procedure SetLookAt3d(x,y,z: Double);
- procedure SetPerspective(a: boolean);
-
- Procedure SetRange(aVal:Double; AdjustAngle:Boolean);
- // set the range and if adjust then calc a viewangle}
- Procedure SetAngle(aVal:Double; AdjustRange:Boolean);
- //Set the view angle and adjust angle if adjustrange=true}
- Function Distance:Double;
- // distance between position and lookat
- Function MaxViewPrism(aScale:Single):tGLPoint; //Max X,Y znd Z ocvered in viewport
- // and scale by the scale factor
- Function MinViewPrism(aScale:Single):tGLPoint; //Min X,Y znd Z ocvered in viewport
- // max and min values for view prism
- // and scale by the scale factor
- Function GetBearing:Double;
- Function GetAzimuth:Double;
- Function GetAngleFromVertical:Double;
- Procedure SetViewPoint(aPt:vViewFrom);
- Procedure CopyValuesFrom(aPt:TViewFrame);
- //set the values from the supplied Frame
- Function ShiftLookAt(aDist:Double):Boolean;
- // shift the lookat away from the viewer by the supplied dist
-
- property Scale:Double Read fScale write SetScale;
- property Position: tGLPoint read fViewer write SetViewerPos;
- property LookAt: tGLPoint read fLookAt write fLookAt;
- property UpVector: tGLPoint read fUpVect write fUpVect;
- property Perspective: boolean read fPerspective write SetPerspective;
- Property Headlight:tGLLight read fHeadLight write fHeadLight;
- property AngleFromVert:Double Read GetAngleFromVertical;
- property Bearing:Double Read GetBearing;
- property Azimuth:Double Read GetAzimuth;
- Property Range:Double Read fRange;
- Property ViewAngle:Double Read fViewAngle;
- Property ScreenZ:Double Read fScreenZ write fScreenZ;
- Property XRadius:Double Read fXRadius write SetXRadius;
- Property YRadius:Double Read fYRadius write SetYRadius;
- Property ZRadius:Double Read fZRadius write SetZRadius;
- end;
-
-
- const
- DefaultUpVector: tGLPoint = (x:0;y:0;z:1);
- x_vector: tGLPoint = (x:1;y:0;z:0);
- y_vector: tGLPoint = (x:0;y:1;z:0);
- z_vector: tGLPoint = (x:0;y:0;z:1);
-
- // extracted from Tims glViewFr unit
- function AbstractRotateAboutLookAt(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
- function AbstractRotateAboutViewer(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
-
- {*********************************************}
- implementation
- {*********************************************}
-
- uses
- Math ;
-
- const
- pi180 = pi/180;
- small = 0.0001;
- (**********************************************************)
- function AbstractRotateAboutViewer(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
- var
- r0, r1: single;
- Pos, View: tGLPoint;
- begin
- VerAng:= VerAng*pi180;
- HorAng:= HorAng*pi180;
- //assumes up-vector is normalised and maintained perpendicular
- //to view-vector.
- {subtract origin}
- Pos.x:= LookAt.x - Viewer.x;
- Pos.y:= LookAt.y - Viewer.y;
- Pos.z:= LookAt.z - Viewer.z;
- View:= Pos; //view_vector
- {save radius so move along sphere}
- r0:= sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
- //y-rotations cause ball to turn in plane of view-vector and up-vector
- //so add up-vector to viewer
- //Note: dist to move is r * theta (in radians)
- Pos.x:= Pos.x - UpVect.x*VerAng*r0;
- Pos.y:= Pos.y - UpVect.y*VerAng*r0;
- Pos.z:= Pos.z - UpVect.z*VerAng*r0;
- //x-rotations cause ball to turn perpendicular to plane of view-vector
- //and up-vector so add cross product to viewer
- //Note: dist to move is r * theta (in radians) but must divide by
- //magnitude of cross-product vectors = r * 1.
- Pos.x:= Pos.x + (View.y*UpVect.z - View.z*UpVect.y)*HorAng;
- Pos.y:= Pos.y + (View.z*UpVect.x - View.x*UpVect.z)*HorAng;
- Pos.z:= Pos.z + (View.x*UpVect.y - View.y*UpVect.x)*HorAng;
- {drop point onto sphere}
- r1:= r0/sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
- LookAt.x:= Viewer.x + r1*Pos.x;
- LookAt.y:= Viewer.y + r1*Pos.y;
- LookAt.z:= Viewer.z + r1*Pos.z;
- {must also push up-vector in same direction as y-rotation so
- add view vector to upvector and normalise}
- UpVect.x:= UpVect.x - View.x*VerAng/r0;
- UpVect.y:= UpVect.y - View.y*VerAng/r0;
- UpVect.z:= UpVect.z - View.z*VerAng/r0;
- r1:= sqrt(sqr(UpVect.x)+sqr(UpVect.y)+sqr(UpVect.z));
- UpVect.x:= UpVect.x/r1;
- UpVect.y:= UpVect.y/r1;
- UpVect.z:= UpVect.z/r1;
- Result:= true;
- end;
- {*********************************************}
- function AbstractRotateAboutLookAt(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
- {moves the fViewer about fLookAt}
- var
- r0, r1: single;
- Pos, View: tGLPoint;
- begin
- VerAng:= VerAng*pi180;
- HorAng:= HorAng*pi180;
- //assumes up-vector is normalised and maintained perpendicular
- //to view-vector.
- {subtract origin}
- Pos.x:= Viewer.x - Lookat.x;
- Pos.y:= Viewer.y - Lookat.y;
- Pos.z:= Viewer.z - Lookat.z;
- View:= Pos; //view_vector
- {save radius so move along sphere}
- r0:= sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
- //y-rotations cause ball to turn in plane of view-vector and up-vector
- //so add up-vector to viewer
- //Note: dist to move is r * theta (in radians)
- Pos.x:= Pos.x + UpVect.x*VerAng*r0;
- Pos.y:= Pos.y + UpVect.y*VerAng*r0;
- Pos.z:= Pos.z + UpVect.z*VerAng*r0;
- //x-rotations cause ball to turn perpendicular to plane of view-vector
- //and up-vector so add cross product to viewer
- //Note: dist to move is r * theta (in radians) but must divide by
- //magnitude of cross-product vectors = r and 1.
- Pos.x:= Pos.x + (View.y*UpVect.z - View.z*UpVect.y)*HorAng;
- Pos.y:= Pos.y + (View.z*UpVect.x - View.x*UpVect.z)*HorAng;
- Pos.z:= Pos.z + (View.x*UpVect.y - View.y*UpVect.x)*HorAng;
- {drop point onto sphere}
- r1:= r0/sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
- Viewer.X:= LookAt.x + r1*Pos.x;
- Viewer.Y:= LookAt.y + r1*Pos.y;
- Viewer.Z:= LookAt.z + r1*Pos.z;
-
- {must also push up-vector in same direction as y-rotation so
- add view vector to upvector and normalise}
- UpVect.x:= UpVect.x - View.x*VerAng/r0;
- UpVect.y:= UpVect.y - View.y*VerAng/r0;
- UpVect.z:= UpVect.z - View.z*VerAng/r0;
- r1:= sqrt(sqr(UpVect.x)+sqr(UpVect.y)+sqr(UpVect.z));
- UpVect.x:= UpVect.x/r1;
- UpVect.y:= UpVect.y/r1;
- UpVect.z:= UpVect.z/r1;
-
- Result:= true;
- end;
- {*********************************************}
- {*********************************************}
- constructor TViewFrame.Create;
- begin
- inherited Create;
- fScale:= 1;
- with fViewer do begin x:=0; y:=100; z:=0; end;
- with fLookAt do begin x:=0; y:=0; z:=0; end;
- with fUpVect do begin x:=0; y:=0; z:=1; end;
- fRange := DefaultSize;
- fViewAngle:= DefaultAngle;
- XRadius := DefaultSize;
- Yradius := DefaultSize;
- ZRadius := DefaultSize;
- fPerspective:= false;
- SetUpEyePositions;
- end;
- {*********************************************}
- function TViewFrame.Duplicate: TViewFrame;
- var
- p: TViewFrame;
- begin
- p:= TViewFrame.Create;
- p.fViewer:=fViewer;
- p.fLookAt:=fLookAt;
- p.fUpVect:= fUpVect;
- p.fLeftEye:=fLeftEye;
- p.fRightEye:=fRightEye;
- p.fOrigin:=fOrigin;
- p.fRange := fRange;
- p.fViewAngle:= fViewAngle;
- p.fScreenZ:= fScreenZ;
- p.fScale:= fScale;
- p.XRadius:= XRadius;
- p.YRadius:= YRadius;
- p.ZRadius:= ZRadius;
- p.fPerspective:= fPerspective;
- Result:= p;
- end;
- (****************************************)
- procedure TViewFrame.SetViewer3s(x,y,z: single);
- begin
- fViewer.x:= x;
- fViewer.y:= y;
- fViewer.z:= z;
- fOrigin:=fViewer;
- If Assigned(fHeadLight) then
- fHeadLight.PositionLight(fViewer);
- SetUpEyePositions;
- end;
- (****************************************)
- procedure TViewFrame.SetLookAt3s(x,y,z: single);
- begin
- fLookAt.x:= x;
- fLookAt.y:= y;
- fLookAt.z:= z;
- end;
- (****************************************)
- Procedure TViewFrame.SetScale(aVal:Double);
- Var MultVal:Double;
- Begin
- If (fScale=aVal) or (fScale=0) then exit;
- MultVal:=aVal/fScale;
- fRange:= fRange*MultVal;
- XRadius:= XRadius*MultVal;
- Yradius:= YRadius*MultVal;
- ZRadius:= ZRadius*MultVal;
- fScale:=aVal;
- with fViewer do SetViewer3d(x*MultVal,y*MultVal,z*MultVal);
- with fLookAt do
- begin x:=x*MultVal; y:=y*MultVal; z:=z*MultVal; end;
- end;
- (****************************************)
- procedure TViewFrame.SetUpVector3s(x,y,z: single);
- begin
- fUpVect.x:= x;
- fUpVect.y:= y;
- fUpVect.z:= z;
- end;
-
- //jh mod
- (****************************************)
- procedure TViewFrame.SetViewer3d(x,y,z: Double);
- begin
- fViewer.x:= x;
- fViewer.y:= y;
- fViewer.z:= z;
- fOrigin:=fViewer;
- If Assigned(fHeadLight) then
- fHeadLight.PositionLight(fViewer);
- SetUpEyePositions;
- end;
- (****************************************)
- procedure TViewFrame.SetLookAt3d(x,y,z: Double);
- begin
- fLookAt.x:= x;
- fLookAt.y:= y;
- fLookAt.z:= z;
- end;
- (****************************************)
- Function TViewFrame.GetBearing:Double;
- Var B,A:Double;
- Begin
- Result:=0;
- If BearingAndAzimuth(fViewer,fLookAt,B,A) then
- Result:=B;
- end;
- (****************************************)
- Function TViewFrame.GetAzimuth:Double;
- Var B,A:Double;
- Begin
- Result:=0;
- If BearingAndAzimuth(fViewer,fLookAt,B,A) then
- Result:=A;
- end;
- (****************************************)
- Function TViewFrame.GetAngleFromVertical:Double;
- Var A:Double;
- Begin
- Result:=0;
- If AngleFromVertical(fViewer,fLookAt,A) then
- Result:=A;
- end;
- (****************************************)
- Procedure TViewFrame.SetViewPoint(aPt:vViewFrom);
- Begin
- Case aPt of
- vCentrePt:fViewer:=fOrigin;
- vLeftEye:fViewer:=fLeftEye;
- vRightEye:fViewer:=fRightEye;
- end;
- If Assigned(fHeadLight) then
- fHeadLight.PositionLight(fViewer);
- end;
- (****************************************)
- Procedure TViewFrame.CopyValuesFrom(aPt:TViewFrame);
- //set the values from the supplied Frame
- Begin
- If not assigned(aPt) then exit;
- fViewer:=aPt.fViewer;
- fLookAt:= aPt.fLookAt;
- fUpVect:= aPt.fUpVect;
- fLeftEye:=aPt.fLeftEye;
- fRightEye:=aPt.fRightEye;
- fOrigin:=aPt.fOrigin;
- fRange := aPt.fRange;
- fViewAngle:= aPt.fViewAngle;
- fScreenZ:= aPt.fScreenZ;
- fScale:= aPt.fScale;
- XRadius:= aPt.XRadius;
- YRadius:= aPt.YRadius;
- ZRadius:= aPt.ZRadius;
- fPerspective:= aPt.fPerspective;
- end;
- (****************************************)
-
- procedure TViewFrame.SetPerspective(A: boolean);
- begin
- fPerspective:= a;
- end;
- (****************************************)
-
- Procedure TViewFrame.SetRange(aVal:Double; AdjustAngle:Boolean);
- // set the range and if adjust then calc a viewangle}
- Var dist,TempVal:Double;
-
- Begin
- If fRange=aVal then exit;
- fRange:=aVal;
- If not adjustAngle then exit;
- dist:=Distance;
- If fRange=0 then fRange:=1;
- TempVal:=fRange/Dist;
- TempVal:=arcTan(TempVal)*(180/Pi);
- fViewangle:=TempVal*2;
- If fViewAngle>180 then fViewAngle:=179;
- end;
- {*********************************************}
- Procedure TViewFrame.SetAngle(aVal:Double; AdjustRange:Boolean);
- //Set the view angle and adjust angle if adjustrange=true}
- Begin
-
- end;
- {*********************************************}
- Function TViewFrame.Distance:Double;
- // distance between position and lookat
- Begin
- Result:=sqrt(Sqr(Position.X-LookAt.X)+
- Sqr(Position.y-LookAt.y) +
- Sqr(Position.z-LookAt.z));
- If abs(Result)<0.0001 then result:=0.0001;
- end;
- {*********************************************}
- Function TViewFrame.MaxViewPrism(aScale:Single):tGLPoint; //Max X,Y znd Z ocvered in viewport
- Begin
- Result.X:=LookAt.X+abs(fRange*aScale);
- Result.Y:=LookAt.Y+abs(fRange*aScale);
- Result.Z:=LookAt.Z+abs(fRange*aScale);
- end;
- {*********************************************}
- Function TViewFrame.MinViewPrism(aScale:Single):tGLPoint; //Min X,Y znd Z ocvered in viewport
- // max and min values for view prism
- Begin
- Result.X:=LookAt.X-abs(fRange*aScale);
- Result.Y:=LookAt.Y-abs(fRange*aScale);
- Result.Z:=LookAt.Z-abs(fRange*aScale);
- end;
- {*********************************************}
- function TViewFrame.RotateAboutViewer(HorAng,VerAng: single): boolean;
- Begin
- Result:= AbstractRotateAboutViewer(fViewer,fLookAt,fUpVect,HorAng,VerAng);
- end;
- (**********************************************************)
- function TViewFrame.RotateAboutLookAt(HorAng,VerAng: single): boolean;
- var TempPt:tGLPoint;
- Begin
- TempPt:=fViewer;
- Result:=AbstractRotateAboutLookAt(TempPt,fLookAt,fUpVect,HorAng,VerAng);
- SetViewer3d(TempPt.X,TempPt.Y,TempPt.Z);
- end;
- (**********************************************************)
- Procedure TViewFrame.SetUpEyePositions;
- Var TempVec :tGLPoint;
- {dist,}HAng:Double;
- Begin
- fLeftEye:=fViewer;
- fRightEye:=fViewer;
- HAng:=EyeOffset;
- (*Dist:=Distance;
- HAng:=ArcTan2(EyeOffset,(2*Dist))/pi180;*)
- TempVec:=fUpVect;
- AbstractRotateAboutLookAt(fLeftEye,fLookAt,TempVec,HAng,0);
- TempVec:=fUpVect;
- AbstractRotateAboutLookAt(fRightEye,fLookAt,TempVec,-HAng,0);
- end;
- (**********************************************************)
- Procedure TViewFrame.SetViewerPos(aVal:tGLPoint);
- Begin
- SetViewer3d(aVal.X,aVal.Y,aVal.Z);
- end;
- (**********************************************************)
- Procedure TViewFrame.SetXRadius(aVal:Double);
- Begin
- If fXRadius=aVal then exit;
- fXRadius:=aVal;
- If fXRadius<MinCubeSize then fXRadius:=MinCubeSize;
- end;
- (**********************************************************)
- Procedure TViewFrame.SetYRadius(aVal:Double);
- Begin
- If fYRadius=aVal then exit;
- fYRadius:=aVal;
- If fYRadius<MinCubeSize then fYRadius:=MinCubeSize;
- end;
- (**********************************************************)
- Procedure TViewFrame.SetZRadius(aVal:Double);
- Begin
- If fZRadius=aVal then exit;
- fZRadius:=aVal;
- If fZRadius<MinCubeSize then fZRadius:=MinCubeSize;
- end;
- (**********************************************************)
-
- function TViewFrame.RotateUpVector(Ang: single): boolean;
- {rotate view about line from Viewer to LookAt}
- var
- r1: single;
- View: tGLPoint;
-
- begin
- //assumes up-vector is normalised and maintained perpendicular
- //to view-vector.
- {subtract origin}
- View.x:= fViewer.x - fLookat.x;
- View.y:= fViewer.y - fLookat.y;
- View.z:= fViewer.z - fLookat.z; //view_vector
- {convert to radians, divide by radius}
- Ang:= Ang*pi180/sqrt(sqr(View.x)+sqr(View.y)+sqr(View.z));
- //rotation is perpendicular to plane of view-vector and up-vector
- //so add cross product to up-vector
- //Note: dist to move is r * theta (in radians) but must divide by
- //magnitude of cross-product vectors = r and 1.
- fUpVect.x:= fUpVect.x + (View.y*fUpVect.z - View.z*fUpVect.y)*Ang;
- fUpVect.y:= fUpVect.y + (View.z*fUpVect.x - View.x*fUpVect.z)*Ang;
- fUpVect.z:= fUpVect.z + (View.x*fUpVect.y - View.y*fUpVect.x)*Ang;
- r1:= 1/sqrt(sqr(fUpVect.x)+sqr(fUpVect.y)+sqr(fUpVect.z));
- fUpVect.x:= fUpVect.x*r1;
- fUpVect.y:= fUpVect.y*r1;
- fUpVect.z:= fUpVect.z*r1;
- Result:= true;
- end;
- (************************************************************)
- Function TViewFrame.ShiftLookAt(aDist:Double):Boolean;
- // shift the lookat away from the viewer by the supplied dist
- var
- s, xDist, yDist, zDist: single;
- begin
- s:= DistanceBetween(fViewer,fLookAt);
- Result:= s<>0;
- if Result then
- begin
- xDist:= (fLookAt.x-fViewer.x)*aDist/s;
- yDist:= (fLookAt.y-fViewer.y)*aDist/s;
- zDist:= (fLookAt.z-fViewer.z)*aDist/s;
-
- with fLookAt do
- begin
- x:=x+xDist; y:=y+yDist; z:=z+zDist;
- end;
- end;
- Result:= true;
- end;
- (************************************************************)
- function TViewFrame.AdvanceToLookAt(Dist: single): boolean; {and rotate HorAng as well?}
- {Move fViewer and fLookAt Dist in direction of joining vector.
- Dist can be pos or neg.}
- var
- s, xDist, yDist, zDist: single;
- begin
- s:= DistanceBetween(fViewer,fLookAt);
- Result:= s<>0;
- if Result then
- begin
- xDist:= (fLookAt.x-fViewer.x)*Dist/s;
- yDist:= (fLookAt.y-fViewer.y)*Dist/s;
- zDist:= (fLookAt.z-fViewer.z)*Dist/s;
-
- with fViewer do
- SetViewer3d(x+xDist,y+yDist,z+zDist);
-
- with fLookAt do
- begin
- x:=x+xDist; y:=y+yDist; z:=z+zDist;
- end;
- end;
- Result:= true;
- end;
-
- procedure TViewFrame.MovePosition(DeltaX,DeltaY,DeltaZ: single);
- begin
- with fViewer do
- SetViewer3d(x+DeltaX,y+DeltaY,z+DeltaZ);
- end;
-
- procedure TViewFrame.MoveFrame(DeltaX,DeltaY,DeltaZ: single);
- begin
- with fViewer do
- SetViewer3d(x+DeltaX,y+DeltaY,z+DeltaZ);
-
- With fLookAt do
- Begin
- X:=X+DeltaX;
- Y:=Y+DeltaY;
- Z:=Z+DeltaZ;
- end;
- end;
-
- function TViewFrame.FlyBy(Speed,RollAng,PitchAng: single): boolean;
- begin
- RotateAboutViewer(RollAng,-PitchAng);
- RotateUpVector(-RollAng);
- AdvanceToLookAt(Speed);
- Result:= true;
- end;
-
- end.
-